#include <iostream>
#include <string>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

const int NTP_PORT = 123;
const long JAN_1ST_1900 = 2415021L;

struct NtpPacket {
    uint8_t li_vn_mode;
    uint8_t stratum;
    uint8_t poll;
    uint8_t precision;
    uint32_t rootDelay;
    uint32_t rootDispersion;
    uint32_t refId;
    uint32_t refTm_s;
    uint32_t refTm_f;
    uint32_t origTm_s;
    uint32_t origTm_f;
    uint32_t rxTm_s;
    uint32_t rxTm_f;
    uint32_t txTm_s;
    uint32_t txTm_f;
};

void getNtpTime(time_t t, uint32_t* seconds, uint32_t* fraction) {
    *seconds = htonl((uint32_t)(t + 2208988800UL));
    *fraction = htonl((uint32_t)((double)rand() / RAND_MAX * 0xFFFFFFFF));
}

time_t parseDateTime(const std::string& datetime) {
    std::tm tm = {};
    std::istringstream ss(datetime);
    ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
    if (ss.fail()) {
        throw std::runtime_error("Failed to parse datetime string");
    }
    return mktime(&tm);
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " \"YYYY-MM-DD HH:MM:SS\"" << std::endl;
        return 1;
    }

    time_t fixedTime;
    try {
        fixedTime = parseDateTime(argv[1]);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "WSAStartup failed" << std::endl;
        return 1;
    }

    SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET) {
        std::cerr << "socket() failed: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }

    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(NTP_PORT);

    if (bind(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "bind() failed: " << WSAGetLastError() << std::endl;
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    std::cout << "NTP server running on port " << NTP_PORT 
              << " with fixed time: " << argv[1] << std::endl;

    while (true) {
        sockaddr_in clientAddr;
        int clientAddrLen = sizeof(clientAddr);
        NtpPacket packet;

        int bytesReceived = recvfrom(sock, (char*)&packet, sizeof(NtpPacket), 0,
                                    (sockaddr*)&clientAddr, &clientAddrLen);
        if (bytesReceived == SOCKET_ERROR) {
            std::cerr << "recvfrom() failed: " << WSAGetLastError() << std::endl;
            continue;
        }

        memset(&packet, 0, sizeof(NtpPacket));
        packet.li_vn_mode = 0x1C;
        packet.stratum = 1;
        packet.poll = 10;
        packet.precision = 0xFA;

        getNtpTime(fixedTime, &packet.refTm_s, &packet.refTm_f);

        time_t now = time(nullptr);
        getNtpTime(now, &packet.origTm_s, &packet.origTm_f);

        getNtpTime(fixedTime, &packet.rxTm_s, &packet.rxTm_f);
        getNtpTime(fixedTime, &packet.txTm_s, &packet.txTm_f);

        if (sendto(sock, (char*)&packet, sizeof(NtpPacket), 0,
                 (sockaddr*)&clientAddr, clientAddrLen) == SOCKET_ERROR) {
            std::cerr << "sendto() failed: " << WSAGetLastError() << std::endl;
        }
    }

    closesocket(sock);
    WSACleanup();
    return 0;
}